home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / PROGRAMM / CC_C / 1199.ZIP / CLIB.ARC < prev    next >
Text File  |  1988-06-15  |  53KB  |  2,077 lines

  1. >>> CLIB.H 1617
  2. /*
  3. ** CLIB.H -- Definitions for Small-C library functions.
  4. **
  5. ** Copyright 1983  L. E. Payne and J. E. Hendrix
  6. */
  7.  
  8. /*
  9. ** Misc parameters
  10. */
  11. #define MAXFILES 20  /* maximum open files */
  12. #define DOSEOF   26  /* DOS end-of-file byte */
  13. #define ARCHIVE  32  /* file archive bit */
  14.  
  15. /*
  16. ** DOS function calls
  17. */
  18. #define CREATE   60  /* make file */
  19. #define OPEN     61  /* open file */
  20. #define CLOSE    62  /* close file or device */
  21. #define READ     63  /* read from a file */
  22. #define WRITE    64  /* write to a file */
  23. #define DELETE   65  /* delete file */
  24. #define SEEK     66  /* seek within a file */
  25. #define CONTROL  68  /* control device */
  26. #define FORCE    70  /* force use of a handle */
  27. #define RETDOS   76  /* close files and return to DOS */
  28. #define FNDFIL   78  /* find first occurrence of a file */
  29. #define FNDNXT   79  /* find next occurrence of a file */
  30. #define RENAME   86  /* rename file */
  31.  
  32. /*
  33. ** File status bits
  34. */
  35. #define OPNBIT   1  /* open condition */
  36. #define EOFBIT   2  /* end-of-file condition */
  37. #define ERRBIT   4  /* error condition */
  38.  
  39. /*
  40. ** File positioning origins
  41. */
  42. #define FROM_BEG  0  /* from beginning of file */
  43. #define FROM_CUR  1  /* from current position */
  44. #define FROM_END  2  /* from end of file */
  45.  
  46. /*
  47. ** Buffer usage codes
  48. ** NULL means the buffer is not used.
  49. */
  50. #define EMPTY     1  /* buffer is currently empty */
  51. #define IN        2  /* buffer is currently holding input data */
  52. #define OUT       3  /* buffer is currently holding output data */
  53.  
  54. /*
  55. ** ASCII characters
  56. */
  57. #define ABORT    3
  58. #define RUB      8
  59. #define PAUSE   19
  60. #define WIPE    24
  61. #define DEL    127
  62.  
  63. >>> ABS.C 117
  64. /*
  65. ** abs -- returns absolute value of nbr
  66. */
  67. abs(nbr)  int nbr; {
  68.   if(nbr < 0) return (-nbr);
  69.   return (nbr);
  70.   }
  71.  
  72. >>> ATOI.C 259
  73. /*
  74. ** atoi(s) - convert s to integer.
  75. */
  76. atoi(s) char *s; {
  77.   int sign, n;
  78.   while(isspace(*s)) ++s;
  79.   sign = 1;
  80.   switch(*s) {
  81.     case '-': sign = -1;
  82.     case '+': ++s;
  83.     }
  84.   n = 0;
  85.   while(isdigit(*s)) n = 10 * n + *s++ - '0';
  86.   return (sign * n);
  87.   }
  88.  
  89. >>> ATOIB.C 435
  90. /*
  91. ** atoib(s,b) - Convert s to "unsigned" integer in base b.
  92. **              NOTE: This is a non-standard function.
  93. */
  94. atoib(s, b) char *s; int b; {
  95.   int n, digit;
  96.   n = 0;
  97.   while(isspace(*s)) ++s;
  98.   while((digit = (127 & *s++)) >= '0') {
  99.     if(digit >= 'a')      digit -= 87;
  100.     else if(digit >= 'A') digit -= 55;
  101.     else                  digit -= '0';
  102.     if(digit >= b) break;
  103.     n = b * n + digit;
  104.     }
  105.   return (n);
  106.   }
  107.  
  108.  
  109. >>> AUXBUF.C 786
  110. #include "stdio.h"
  111. #include "clib.h"
  112. extern int
  113.   _bufsiz[MAXFILES],  /* size of buffer */
  114.   _bufptr[MAXFILES];  /* aux buffer address */
  115.  
  116. /*
  117. ** auxbuf -- allocate an auxiliary input buffer for fd
  118. **   fd = file descriptor of an open file
  119. ** size = size of buffer to be allocated
  120. ** Returns NULL on success, else ERR.
  121. ** Note: Ungetc() still works.
  122. **       A 2nd call allocates a new buffer replacing old one.
  123. **       If fd is a device, buffer is allocated but ignored.
  124. **       Buffer stays allocated when fd is closed or new one is allocated.
  125. **       May be used on a closed fd.
  126. */
  127. auxbuf(fd, size) int fd; char *size; {   /* fake unsigned */
  128.   if(!size || avail(NO) < size) return (ERR);
  129.   _bufptr[fd] = malloc(size);
  130.   _bufsiz[fd] = size;
  131.   _empty(fd, NO);
  132.   return (NULL);
  133.   }
  134.  
  135. >>> AVAIL.C 347
  136. extern char *_memptr;
  137. /*
  138. ** Return the number of bytes of available memory.
  139. ** In case of a stack overflow condition, if 'abort'
  140. ** is non-zero the program aborts with an 'S' clue,
  141. ** otherwise zero is returned.
  142. */
  143. avail(abort) int abort; {
  144.   char x;
  145.   if(&x < _memptr) {
  146.     if(abort) exit(1);
  147.     return (0);
  148.     }
  149.   return (&x - _memptr);
  150.   }
  151.  
  152. >>> BSEEK.C 727
  153. #include "stdio.h"
  154. #include "clib.h"
  155. extern int _nextc[], _bufuse[];
  156. /*
  157. ** Position fd to the character in file indicated by "offset."
  158. ** "Offset" is the address of a long integer or array of two
  159. ** integers containing the offset, low word first.
  160. ** 
  161. **     BASE     OFFSET-RELATIVE-TO
  162. **       0      beginning of file
  163. **       1      current byte in file
  164. **       2      end of file (minus offset)
  165. **
  166. ** Returns NULL on success, else EOF.
  167. */
  168. bseek(fd, offset, base) int fd, offset[], base; {
  169.   int hi, lo;
  170.   if(!_mode(fd) || !_bufuse[fd]) return (EOF);
  171.   if(_adjust(fd)) return (EOF);
  172.   lo = offset[0];
  173.   hi = offset[1];
  174.   if(!_seek(base, fd, &hi, &lo)) return (EOF);
  175.   _nextc[fd] = EOF;
  176.   _clreof(fd);
  177.   return (NULL);
  178.   }
  179.  
  180. >>> BTELL.C 447
  181. #include "stdio.h"
  182. #include "clib.h"
  183. extern int _bufuse[];
  184. /*
  185. ** Retrieve offset to next character in fd.
  186. ** "Offset" must be the address of a long int or
  187. ** a 2-element int array.  The offset is placed in
  188. ** offset in low, high order.
  189. */
  190. btell(fd, offset) int fd, offset[]; {
  191.   if(!_mode(fd) || !_bufuse[fd]) return (EOF);
  192.   if(_adjust(fd)) return (EOF);
  193.   offset[0] = offset[1] = 0;
  194.   _seek(FROM_CUR, fd, offset+1, offset);
  195.   return (NULL);
  196.   }
  197. >>> CALL.ASM 3939
  198. ;
  199. ; Small-C Run Time Library for MS/PC-DOS
  200. ;
  201.         extrn   __main: near
  202.         extrn    _exit: near
  203.         extrn   __memptr: word
  204.  
  205. data   segment public
  206.         dw      1
  207. data   ends
  208.  
  209. stack   segment stack
  210.         dw      32 dup(?)
  211. stack   ends
  212.  
  213. code    segment public
  214.         assume  cs:code
  215. start:
  216.         mov     ax,data         ; set data segment for program
  217.         mov     ds,ax
  218.         mov     ax,es:[2]       ; paragraphs of memory on system
  219.         sub     ax,data         ; paragraphs beyond code segment
  220.         cmp     ah,10h          ; more than 64K?
  221.         jb      start_1         ; no
  222.         mov     ax,1000h        ; only use 64K
  223. start_1:
  224.         mov     cl,4
  225.         shl     ax,cl           ; byte offset to end of data/free/stack
  226.         cli                     ; disable interrupts
  227.         mov     bx,ds
  228.         mov     ss,bx           ; make data and stack segments coincide
  229.         mov     sp,ax           ; top of stack = end of data/free/stack
  230.         push    ax              ; force sp non-zero (if 64K used)
  231.         sti                     ; reenable interrupts
  232.         mov     ax,stack        ; paragraph following data
  233.         sub     ax,data         ; number of data paragraphs
  234.         shl     ax,cl           ; number of data bytes (offset to free/stack)
  235.         mov     bx,ax
  236.         inc     bh              ; adjust for minimum stack space
  237.         cmp     bx,sp           ; enough memory?
  238.         jb      start_2         ; yes
  239.         mov     ax,1            ; no, terminate with exit code 1
  240.         push    ax
  241.         call    _exit
  242. start_2:
  243.         mov     __memptr,ax     ; set memory allocation pointer
  244. ;
  245. ; ------------ release unused memory -----------
  246. ; ------ cannot run debug with this code -------
  247. ;        mov     bx,sp
  248. ;        mov     ah,4AH
  249. ;        int     21H
  250. ; ----------------------------------------------
  251. ;
  252. ; make sure that es -> psp, because __main requires it
  253. ;
  254.         jmp     __main          ; __main never returns
  255.  
  256.         public  _ccargc
  257. _ccargc:
  258.         mov     al,cl
  259.         xor     ah,ah
  260.         ret
  261.  
  262. ;
  263. ; Test if Secondary (BX) <oper> Primary (AX)
  264. ;-------------------------- MASM version
  265. ;compare macro   name, cond
  266. ;        public  __&name
  267. ;__&name:
  268. ;        cmp     ax,bx
  269. ;        j&cond  true
  270. ;        xor     ax,ax   ; returns zero
  271. ;        ret
  272. ;        endm
  273. ;-------------------------- ASM version
  274. compare macro   name, cond
  275.         public  __?1
  276. __?1:
  277.         cmp     ax,bx
  278.         j?2     true
  279.         xor     ax,ax   ; returns zero
  280.         ret
  281.         endm
  282. ;--------------------------
  283.         compare ult,a
  284.         compare ugt,b
  285.         compare ule,ae
  286.         compare uge,be
  287.         compare eq,e
  288.         compare ne,ne
  289.         compare lt,g
  290.         compare gt,l
  291.         compare le,ge
  292.         compare ge,le
  293.  
  294. ;
  295. ; Logical Negate of Primary
  296. ;
  297.         public  __lneg
  298. __lneg:
  299.         or      ax,ax
  300.         jnz     false
  301. true:   mov     ax,1    ; returns one
  302.         ret
  303. false:  xor     ax,ax   ; returns zero
  304.         ret
  305. ;
  306. ;
  307. ; execute "switch" statement
  308. ;
  309. ;  ax  =  switch value
  310. ; (sp) -> switch table
  311. ;         dw addr1, value1
  312. ;         dw addr2, value2
  313. ;         ...
  314. ;         dw 0
  315. ;        [jmp default]
  316. ;         continuation
  317. ;
  318.         public  __switch
  319. __switch:
  320.         pop     bx              ; bx -> switch table
  321.         jmp     skip            ; skip the pre-increment
  322. back:
  323.         add     bx,4
  324. skip:   mov     cx,cs:[bx]
  325.         jcxz    default         ; end of table -- jump out
  326.         cmp     ax,cs:[bx+2]
  327.         jnz     back
  328.         jmp     cx              ; match -- jump to case
  329. default:
  330.         inc     bx
  331.         inc     bx
  332.         jmp     bx              ; jump to default/continuation
  333. ;
  334. ; dummy entry point to resolve the external reference _LINK
  335. ; which is no longer generated by Small-C but which exists in
  336. ; library modules and .OBJ files compiled by earlier versions
  337. ; of Small-C
  338.         public  __link
  339. __link: ret
  340.  
  341. code ends
  342.         end     start
  343.  
  344. >>> CALLOC.C 315
  345. #include "stdio.h"
  346. /*
  347. ** Cleared-memory allocation of n items of size bytes.
  348. ** n     = Number of items to allocate space for.
  349. ** size  = Size of the items in bytes.
  350. ** Returns the address of the allocated block,
  351. ** else NULL for failure.
  352. */
  353. calloc(n, size) unsigned n, size; {
  354.   return (_alloc(n*size, YES));
  355.   }
  356.  
  357. >>> CLEARERR.C 152
  358. #include "stdio.h"
  359. #include "clib.h"
  360. extern int _status[];
  361. /*
  362. ** Clear error status for fd.
  363. */
  364. clearerr(fd) int fd; {
  365.   if(_mode(fd)) _clrerr(fd);
  366.   }
  367.  
  368. >>> CSEEK.C 1539
  369. #include "stdio.h"
  370. #include "clib.h"
  371. extern int _nextc[], _bufuse[];
  372. /*
  373. ** Position fd to the 128-byte record indicated by
  374. ** "offset" relative to the point indicated by "base."
  375. ** 
  376. **     BASE     OFFSET-RELATIVE-TO
  377. **       0      first record
  378. **       1      current record
  379. **       2      end of file (last record + 1)
  380. **              (offset should be minus)
  381. **
  382. ** Returns NULL on success, else EOF.
  383. */
  384. cseek(fd, offset, base) int fd, offset, base; {
  385.   int newrec, oldrec, hi, lo;
  386.   if(!_mode(fd) || !_bufuse[fd]) return (EOF);
  387.   if(_adjust(fd)) return (EOF);
  388.   switch (base) {
  389.      case 0: newrec = offset;
  390.              break;
  391.      case 1: oldrec = ctell(fd);
  392.              goto calc;
  393.      case 2: hi = lo = 0;
  394.              if(!_seek(FROM_END, fd, &hi, &lo)) return (EOF);
  395.              oldrec = ((lo >> 7) & 511) | (hi << 9);
  396.      calc:
  397.              newrec = oldrec + offset;
  398.              break;
  399.     default: return (EOF);
  400.     }
  401.   lo = (newrec << 7);       /* convert newrec to long int */
  402.   hi = (newrec >> 9) & 127;
  403.   if(!_seek(FROM_BEG, fd, &hi, &lo)) return (EOF);
  404.   _nextc[fd] = EOF;
  405.   _clreof(fd);
  406.   return (NULL);
  407.   }
  408.  
  409. /*
  410. ** Position fd to the character indicated by
  411. ** "offset" within current 128-byte record.
  412. ** Must be on record boundary.
  413. **
  414. ** Returns NULL on success, else EOF.
  415. */
  416. cseekc(fd, offset) int fd, offset; {
  417.   int hi, lo;
  418.   if(!_mode(fd) || isatty(fd) ||
  419.      ctellc(fd) || offset < 0 || offset > 127) return (EOF);
  420.   hi = 0; lo = offset;
  421.   if(!_seek(FROM_CUR, fd, &hi, &lo)) return (EOF);
  422.   return (NULL);
  423.   }
  424.  
  425. >>> CSYSLIB.C 9708
  426. /*
  427. ** CSYSLIB -- System-Level Library Functions
  428. */
  429.  
  430. #include "stdio.h"
  431. #include "clib.h"
  432.  
  433. /*
  434. ****************** System Variables ********************
  435. */
  436.  
  437. int
  438.   _cnt=1,             /* arg count for main */
  439.   _vec[20],           /* arg vectors for main */
  440.   _status[MAXFILES] = {OPNBIT, OPNBIT, OPNBIT, OPNBIT, OPNBIT},
  441.   _cons  [MAXFILES],  /* fast way to tell if file is the console */
  442.   _nextc [MAXFILES] = {EOF, EOF, EOF, EOF, EOF},
  443.   _bufuse[MAXFILES],  /* current buffer usage: NULL, EMPTY, IN, OUT */
  444.   _bufsiz[MAXFILES],  /* size of buffer */
  445.   _bufptr[MAXFILES],  /* aux buffer address */
  446.   _bufnxt[MAXFILES],  /* address of next byte in buffer */
  447.   _bufend[MAXFILES],  /* address of end-of-data in buffer */
  448.   _bufeof[MAXFILES];  /* true if current buffer ends file */
  449.  
  450. char
  451.  *_memptr,           /* pointer to free memory. */
  452.   _arg1[]="*";       /* first arg for main */
  453.  
  454. /*
  455. *************** System-Level Functions *****************
  456. */
  457.  
  458. /*
  459. **  Process command line, allocate default buffer to each fd,
  460. **  execute main(), and exit to DOS.  Must be executed with es=psp.
  461. **  Small default buffers are allocated because a high price is paid for
  462. **  byte-by-byte calls to DOS.  Tests gave these results for a simple
  463. **  copy program:
  464. **
  465. **          chunk size       copy time in seconds
  466. **              1                    36
  467. **              5                    12
  468. **             25                     6
  469. **             50                     6
  470. */
  471. _main() {
  472.   int fd;
  473.   _parse();
  474.   for(fd = 0; fd < MAXFILES; ++fd) auxbuf(fd, 32);
  475.   if(!isatty(stdin))  _bufuse[stdin]  = EMPTY;
  476.   if(!isatty(stdout)) _bufuse[stdout] = EMPTY;
  477.   main(_cnt, _vec);
  478.   exit(0);
  479.   }
  480.  
  481. /*
  482. ** Parse command line and setup argc and argv.
  483. ** Must be executed with es == psp
  484. */
  485. _parse() {
  486.   char *ptr;
  487. #asm
  488.   mov     cl,es:[80h]  ; get parameter string length
  489.   mov     ch,0       
  490.   push    cx           ; save it
  491.   inc     cx
  492.   push    cx           ; 1st __alloc() arg
  493.   mov     ax,1
  494.   push    ax           ; 2nd __alloc() arg
  495.   call    __alloc      ; allocate zeroed memory for args
  496.   add     sp,4
  497.   mov     [bp-2],ax    ; ptr = addr of allocated memory
  498.   pop     cx
  499.   push    es           ; exchange
  500.   push    ds           ; es         (source)
  501.   pop     es           ;    and
  502.   pop     ds           ;        ds  (destination)
  503.   mov     si,81h       ; source offset
  504.   mov     di,[bp-2]    ; destination offset
  505.   rep     movsb        ; move string
  506.   mov     al,0
  507.   stosb                ; terminate with null byte
  508.   push    es
  509.   pop     ds           ; restore ds
  510. #endasm
  511.   _vec[0]=_arg1;       /* first arg = "*" */
  512.   while (*ptr) {
  513.     if(isspace(*ptr)) {++ptr; continue;}
  514.     if(_cnt < 20) _vec[_cnt++] = ptr;
  515.     while(*ptr) {
  516.       if(isspace(*ptr)) {*ptr = NULL; ++ptr; break;}
  517.       ++ptr;
  518.       }
  519.     }
  520.   }
  521.  
  522. /*
  523. ** Open file on specified fd.
  524. */
  525. _open(fn, mode, fd) char *fn, *mode; int *fd; {
  526.   int rw, tfd;
  527.   switch(mode[0]) {
  528.     case 'r': {
  529.       if(mode[1] == '+') rw = 2; else rw = 0;
  530.       if ((tfd = _bdos2((OPEN<<8)|rw, NULL, NULL, fn)) < 0) return (NO);
  531.       break;
  532.       }
  533.     case 'w': {
  534.       if(mode[1] == '+') rw = 2; else rw = 1;
  535.     create:
  536.       if((tfd = _bdos2((CREATE<<8), NULL, ARCHIVE, fn)) < 0) return (NO);
  537.       _bdos2(CLOSE<<8, tfd, NULL, NULL);
  538.       if((tfd = _bdos2((OPEN<<8)|rw, NULL, NULL, fn)) < 0) return (NO);
  539.       break;
  540.       }
  541.     case 'a': {
  542.       if(mode[1] == '+') rw = 2; else rw = 1;
  543.       if((tfd = _bdos2((OPEN<<8)|rw, NULL, NULL, fn)) < 0) goto create;
  544.       if(_bdos2((SEEK<<8)|FROM_END, tfd, NULL, 0) < 0) return (NO);
  545.       break;
  546.       }
  547.     default: return (NO);
  548.     }
  549.   _empty(tfd, YES);
  550.   if(isatty(tfd)) _bufuse[tfd] = NULL;
  551.   *fd = tfd;
  552.   _cons  [tfd] = NULL;
  553.   _nextc [tfd] = EOF;
  554.   _status[tfd] = OPNBIT;
  555.   return (YES);
  556.   }
  557.  
  558. /*
  559. ** Binary-stream input of one byte from fd.
  560. */
  561. _read(fd) int fd; {
  562.   unsigned char ch;
  563.   if(_nextc[fd] != EOF) {
  564.     ch = _nextc[fd];
  565.     _nextc[fd] = EOF;
  566.     return (ch);
  567.     }
  568.   if(iscons(fd))  return (_getkey());
  569.   if(_bufuse[fd]) return(_readbuf(fd));
  570.   switch(_bdos2(READ<<8, fd, 1, &ch)) {
  571.      case 1:  return (ch);
  572.      case 0: _seteof(fd); return (EOF);
  573.     default: _seterr(fd); return (EOF);
  574.     }
  575.   }
  576.  
  577. /*
  578. ** Fill buffer if necessary, and return next byte.
  579. */
  580. _readbuf(fd) int fd; {
  581.   int got, chunk;
  582.   char *ptr, *max;
  583.   if(_bufuse[fd] == OUT && _flush(fd)) return (EOF);
  584.   while(YES) {
  585.     ptr = _bufnxt[fd];
  586.     if(ptr < _bufend[fd]) {++_bufnxt[fd]; return (*ptr);}
  587.     if(_bufeof[fd]) {_seteof(fd); return (EOF);}
  588.     max = (ptr = _bufend[fd] = _bufptr[fd]) + _bufsiz[fd];
  589.     do {         /* avoid DMA problem on physical 64K boundary */
  590.       if((max - ptr) < 512) chunk = max - ptr;
  591.       else                  chunk = 512;
  592.       ptr += (got = _bdos2(READ<<8, fd, chunk, ptr));
  593.       if(got < chunk) {_bufeof[fd] = YES; break;}
  594.       } while(ptr < max);
  595.     _bufend[fd] = ptr;
  596.     _bufnxt[fd] = _bufptr[fd];
  597.     _bufuse[fd] = IN;
  598.     }
  599.   }
  600.  
  601. /*
  602. ** Binary-Stream output of one byte to fd.
  603. */
  604. _write(ch, fd) int ch, fd; {
  605.   if(_bufuse[fd]) return(_writebuf(ch, fd));
  606.   if(_bdos2(WRITE<<8, fd, 1, &ch) != 1) {
  607.     _seterr(fd);
  608.     return (EOF);
  609.     }
  610.   return (ch);
  611.   }
  612.  
  613. /*
  614. ** Empty buffer if necessary, and store ch in buffer.
  615. */
  616. _writebuf(ch, fd) int ch, fd; {
  617.   char *ptr;
  618.   if(_bufuse[fd] == IN && _backup(fd)) return (EOF);
  619.   while(YES) {
  620.     ptr = _bufnxt[fd];
  621.     if(ptr < (_bufptr[fd] + _bufsiz[fd])) {
  622.       *ptr = ch;
  623.       ++_bufnxt[fd];
  624.       _bufuse[fd] = OUT;
  625.       return (ch);
  626.       }
  627.     if(_flush(fd)) return (EOF);
  628.     }
  629.   }
  630.  
  631. /*
  632. ** Flush buffer to DOS if dirty buffer.
  633. ** Reset buffer pointers in any case.
  634. */
  635. _flush(fd) int fd; {
  636.   int i, j, k, chunk;
  637.   if(_bufuse[fd] == OUT) {
  638.     i = _bufnxt[fd] - _bufptr[fd];
  639.     k = 0;
  640.     while(i > 0) {     /* avoid DMA problem on physical 64K boundary */
  641.       if(i < 512) chunk = i;
  642.       else        chunk = 512;
  643.       k += (j = _bdos2(WRITE<<8, fd, chunk, _bufptr[fd] + k));
  644.       if(j < chunk) {_seterr(fd); return (EOF);}
  645.       i -= j;
  646.       }
  647.     }
  648.   _empty(fd, YES);
  649.   return (NULL);
  650.   }
  651.  
  652. /*
  653. ** Adjust DOS file position to current point.
  654. */
  655. _adjust(fd) int fd; {
  656.   if(_bufuse[fd] == OUT) return (_flush(fd));
  657.   if(_bufuse[fd] == IN ) return (_backup(fd));
  658.   }
  659.  
  660. /*
  661. ** Backup DOS file position to current point.
  662. */
  663. _backup(fd) int fd; {
  664.   int hi, lo;
  665.   if(lo = _bufnxt[fd] - _bufend[fd]) {
  666.     hi = -1;
  667.     if(!_seek(FROM_CUR, fd, &hi, &lo)) {
  668.       _seterr(fd);
  669.       return (EOF);
  670.       }
  671.     }
  672.   _empty(fd, YES);
  673.   return (NULL);
  674.   }
  675.  
  676. /*
  677. ** Set buffer controls to empty status.
  678. */
  679. _empty(fd, mt) int fd, mt; {
  680.   _bufnxt[fd] = _bufend[fd] = _bufptr[fd];
  681.   _bufeof[fd] = NO;
  682.   if(mt) _bufuse[fd] = EMPTY;
  683.   }
  684.  
  685. /*
  686. ** Return fd's open mode, else NULL.
  687. */
  688. _mode(fd) char *fd; {
  689.   if(fd < MAXFILES) return (_status[fd]);
  690.   return (NULL);
  691.   }
  692.  
  693. /*
  694. ** Set eof status for fd and
  695. */
  696. _seteof(fd) int fd; {
  697.   _status[fd] |= EOFBIT;
  698.   }
  699.  
  700. /*
  701. ** Clear eof status for fd.
  702. */
  703. _clreof(fd) int fd; {
  704.   _status[fd] &= ~EOFBIT;
  705.   }
  706.  
  707. /*
  708. ** Set error status for fd.
  709. */
  710. _seterr(fd) int fd; {
  711.   _status[fd] |= ERRBIT;
  712.   }
  713.  
  714. /*
  715. ** Clear error status for fd.
  716. */
  717. _clrerr(fd) int fd; {
  718.   _status[fd] &= ~ERRBIT;
  719.   }
  720.  
  721. /*
  722. ** Allocate n bytes of (possibly zeroed) memory.
  723. ** Entry: n = Size of the items in bytes.
  724. **    clear = "true" if clearing is desired.
  725. ** Returns the address of the allocated block of memory
  726. ** or NULL if the requested amount of space is not available.
  727. */
  728. _alloc(n, clear) unsigned n, clear; {
  729.   char *oldptr;
  730.   if(n < avail(YES)) {
  731.     if(clear) pad(_memptr, NULL, n);
  732.     oldptr = _memptr;
  733.     _memptr += n;
  734.     return (oldptr);
  735.     }
  736.   return (NULL);
  737.   }
  738.  
  739. /*
  740. ** Issue extended BDOS function and return result. 
  741. ** Entry: ax = function code and sub-function
  742. **        bx, cx, dx = other parameters
  743. */
  744. _bdos2(ax, bx, cx, dx) int ax, bx, cx, dx; {
  745. #asm
  746.   push bx         ; preserve secondary register
  747.   mov  dx,[bp+4]
  748.   mov  cx,[bp+6]
  749.   mov  bx,[bp+8]
  750.   mov  ax,[bp+10] ; load DOS function number
  751.   int  21h        ; call bdos
  752.   jnc  __bdos21   ; no error
  753.   neg  ax         ; make error code negative  
  754. __bdos21:
  755.   pop  bx         ; restore secondary register
  756. #endasm
  757.   }
  758.  
  759. /*
  760. ** Issue LSEEK call
  761. */
  762. _seek(org, fd, hi, lo) int org, fd, hi, lo; {
  763. #asm
  764.   push bx         ; preserve secondary register
  765.   mov  bx,[bp+4]
  766.   mov  dx,[bx]    ; get lo part of destination
  767.   mov  bx,[bp+6]
  768.   mov  cx,[bx]    ; get hi part of destination
  769.   mov  bx,[bp+8]  ; get file descriptor
  770.   mov  al,[bp+10] ; get origin code for seek
  771.   mov  ah,42h     ; move-file-pointer function
  772.   int  21h        ; call bdos
  773.   jnc  __seek1    ; error?
  774.   xor  ax,ax      ; yes, return false
  775.   jmp  __seek2 
  776. __seek1:          ; no, set hi and lo
  777.   mov  bx,[bp+4]  ; get address of lo
  778.   mov  [bx],ax    ; store low part of new position
  779.   mov  bx,[bp+6]  ; get address of hi
  780.   mov  [bx],dx    ; store high part of new position
  781.   mov  ax,1       ; return true
  782. __seek2:
  783.   pop  bx         ; restore secondary register
  784. #endasm
  785.   }
  786.  
  787. /*
  788. ** Test for keyboard input
  789. */
  790. _hitkey() {
  791. #asm
  792.   mov  ah,1       ; sub-service = test keyboard
  793.   int  16h        ; call bdos keyboard services
  794.   jnz  __hit1
  795.   xor ax,ax       ; nothing there, return false
  796.   jmp  __hit2
  797. __hit1:
  798.   mov  ax,1       ; character ready, return true
  799. __hit2:
  800. #endasm
  801.   }
  802.  
  803. /*
  804. ** Return next keyboard character
  805. */
  806. _getkey() {
  807. #asm
  808.   mov  ah,0       ; sub-service = read keyboard
  809.   int  16h        ; call bdos keyboard services
  810.   or   al,al      ; special character?
  811.   jnz  __get2     ; no
  812.   mov  al,ah      ; yes, move it to al
  813.   cmp  al,3       ; ctl-2 (simulated null)?
  814.   jne  __get1     ; no
  815.   xor  al,al      ; yes, report zero
  816.   jmp  __get2
  817. __get1:
  818.   add  al,113     ; offset to range 128-245
  819. __get2:
  820.   xor  ah,ah      ; zero ah
  821. #endasm
  822.   }
  823.  
  824. >>> CTELL.C 566
  825. #include "stdio.h"
  826. #include "clib.h"
  827. extern int _bufuse[];
  828. /*
  829. ** Return offset to current 128-byte record.
  830. */
  831. ctell(fd) int fd; {
  832.   int hi, lo;
  833.   if(!_mode(fd) || !_bufuse[fd]) return (-1);
  834.   if(_adjust(fd)) return (-1);
  835.   hi = lo = 0;
  836.   _seek(FROM_CUR, fd, &hi, &lo);
  837.   return ((hi << 9) | ((lo >> 7) & 511));
  838.   }
  839.  
  840. /*
  841. ** Return offset to next byte in current 128-byte record.
  842. */
  843. ctellc(fd) int fd; {
  844.   int hi, lo;
  845.   if(!_mode(fd) || !_bufuse[fd]) return (-1);
  846.   if(_adjust(fd)) return (-1);
  847.   hi = lo = 0;
  848.   _seek(FROM_CUR, fd, &hi, &lo);
  849.   return (lo & 127);
  850.   }
  851.  
  852. >>> DTOI.C 370
  853. #include "stdio.h"
  854. /*
  855. ** dtoi -- convert signed decimal string to integer nbr
  856. **         returns field length, else ERR on error
  857. */
  858. dtoi(decstr, nbr)  char *decstr;  int *nbr;  {
  859.   int len, s;
  860.   if((*decstr)=='-') {s=1; ++decstr;} else s=0;
  861.   if((len=utoi(decstr, nbr))<0) return ERR;
  862.   if(*nbr<0) return ERR;
  863.   if(s) {*nbr = -*nbr; return ++len;} else return len;
  864.   }
  865.  
  866. >>> EXIT.C 447
  867. #include "stdio.h"
  868. #include "clib.h"
  869. /*
  870. ** Close all open files and exit to DOS. 
  871. ** Entry: ec = exit code.
  872. */
  873. exit(ec) int ec; {
  874.   int fd;  char str[4];
  875.   ec &= 255;
  876.   if(ec) {
  877.     left(itou(ec, str, 4));
  878.     fputs("Exit Code: ", stderr);
  879.     fputs(str, stderr);
  880.     fputs("\n", stderr);
  881.     }
  882.   for(fd = 0; fd < MAXFILES; ++fd) fclose(fd);
  883.   _bdos2((RETDOS<<8)|ec, NULL, NULL, NULL);
  884. #asm
  885. _abort: jmp    _exit
  886.         public _abort
  887. #endasm
  888.   }
  889.  
  890. >>> FCLOSE.C 336
  891. #include "stdio.h"
  892. #include "clib.h"
  893. /*
  894. ** Close fd 
  895. ** Entry: fd = file descriptor for file to be closed.
  896. ** Returns NULL for success, otherwise ERR
  897. */
  898. extern int _status[];
  899. fclose(fd) int fd; {
  900.   if(!_mode(fd) || _flush(fd)) return (ERR);
  901.   if(_bdos2(CLOSE<<8, fd, NULL, NULL) == -6) return (ERR);
  902.   return (_status[fd] = NULL);
  903.   }
  904.  
  905. >>> FEOF.C 214
  906. #include "clib.h"
  907. extern int _status[];
  908. /*
  909. ** Test for end-of-file status.
  910. ** Entry: fd = file descriptor
  911. ** Returns non-zero if fd is at eof, else zero.
  912. */
  913. feof(fd) int fd; {
  914.   return (_status[fd] & EOFBIT);
  915.   }
  916.  
  917. >>> FERROR.C 152
  918. #include "stdio.h"
  919. #include "clib.h"
  920. extern _status[];
  921. /*
  922. ** Test for error status on fd.
  923. */
  924. ferror(fd) int fd; {
  925.   return (_status[fd] & ERRBIT);
  926.   }
  927.  
  928. >>> FGETC.C 1083
  929. #include "stdio.h"
  930. #include "clib.h"
  931.  
  932. extern int _nextc[];
  933.  
  934. /*
  935. ** Character-stream input of one character from fd.
  936. ** Entry: fd = File descriptor of pertinent file.
  937. ** Returns the next character on success, else EOF.
  938. */
  939. fgetc(fd) int fd; {
  940.   int ch;                   /* must be int so EOF will flow through */
  941.   if(_nextc[fd] != EOF) {   /* an ungotten byte pending? */
  942.     ch = _nextc[fd];
  943.     _nextc[fd] = EOF;
  944.     return (ch & 255);      /* was cooked the first time */
  945.     }
  946.   while(1) {
  947.     ch = _read(fd);
  948.     if(iscons(fd)) {
  949.       switch(ch) {          /* extra console cooking */
  950.         case ABORT:  exit(2);
  951.         case    CR: _write(CR, stderr); _write(LF, stderr); break;
  952.         case   DEL:  ch = RUB;
  953.         case   RUB:
  954.         case  WIPE:  break;
  955.         default:    _write(ch, stderr);
  956.         }
  957.       }
  958.     switch(ch) {            /* normal cooking */
  959.           default:  return (ch);
  960.       case DOSEOF: _seteof(fd); return (EOF);
  961.       case     CR:  return ('\n');
  962.       case     LF:
  963.       }
  964.     }
  965.   }
  966. #asm
  967. _getc:  jmp     _fgetc
  968.         public  _getc
  969. #endasm
  970.  
  971. >>> FGETS.C 1659
  972. #include "stdio.h"
  973. #include "clib.h"
  974. /*
  975. ** Gets an entire string (including its newline
  976. ** terminator) or size-1 characters, whichever comes
  977. ** first. The input is terminated by a null character.
  978. ** Entry: str  = Pointer to destination buffer.
  979. **        size = Size of the destination buffer.
  980. **        fd   = File descriptor of pertinent file.
  981. ** Returns str on success, else NULL.
  982. */
  983. fgets(str, size, fd) char *str; unsigned size, fd; {
  984.   return (_gets(str, size, fd, 1));
  985.   }
  986.  
  987. /*
  988. ** Gets an entire string from stdin (excluding its newline
  989. ** terminator) or size-1 characters, whichever comes
  990. ** first. The input is terminated by a null character.
  991. ** The user buffer must be large enough to hold the data.
  992. ** Entry: str  = Pointer to destination buffer.
  993. ** Returns str on success, else NULL.
  994. */
  995. gets(str) char *str; {
  996.   return (_gets(str, 32767, stdin, 0));
  997.   }
  998.  
  999. _gets(str, size, fd, nl) char *str; unsigned size, fd, nl; {
  1000.   int backup; char *next;
  1001.   next = str;
  1002.   while(--size > 0) {
  1003.     switch (*next = fgetc(fd)) {
  1004.       case  EOF: *next = NULL;
  1005.                  if(next == str) return (NULL);
  1006.                  return (str);
  1007.       case '\n': *(next + nl) = NULL;
  1008.                  return (str);
  1009.       case  RUB: if(next > str) backup = 1; else backup = 0;
  1010.                  goto backout;
  1011.       case WIPE: backup = next - str;
  1012.         backout: if(iscons(fd)) {
  1013.                    ++size;
  1014.                    while(backup--) {
  1015.                      fputs("\b \b", stderr);
  1016.                      --next; ++size;
  1017.                      }
  1018.                    continue;
  1019.                    }
  1020.         default: ++next;
  1021.       }
  1022.     }
  1023.   *next = NULL;
  1024.   return (str);
  1025.   }
  1026.  
  1027. >>> FOPEN.C 485
  1028. #include "stdio.h"
  1029. #include "clib.h"
  1030. /*
  1031. ** Open file indicated by fn.
  1032. ** Entry: fn   = Null-terminated DOS file name.
  1033. **        mode = "a"  - append
  1034. **               "r"  - read
  1035. **               "w"  - write
  1036. **               "a+" - append update
  1037. **               "r+" - read   update
  1038. **               "w+" - write  update
  1039. ** Returns a file descriptor on success, else NULL.
  1040. */
  1041. fopen(fn, mode) char *fn, *mode; {
  1042.   int fd;
  1043.   if(!_open(fn, mode, &fd)) return (NULL);
  1044.   return (fd);
  1045.   }
  1046.  
  1047. >>> FPRINTF.C 2133
  1048. #include "stdio.h"
  1049. /*
  1050. ** fprintf(fd, ctlstring, arg, arg, ...) - Formatted print.
  1051. ** Operates as described by Kernighan & Ritchie.
  1052. ** b, c, d, o, s, u, and x specifications are supported.
  1053. ** Note: b (binary) is a non-standard extension.
  1054. */
  1055. fprintf(argc) int argc; {
  1056.   int *nxtarg;
  1057.   nxtarg = CCARGC() + &argc;
  1058.   return(_print(*(--nxtarg), --nxtarg));
  1059.   }
  1060.  
  1061. /*
  1062. ** printf(ctlstring, arg, arg, ...) - Formatted print.
  1063. ** Operates as described by Kernighan & Ritchie.
  1064. ** b, c, d, o, s, u, and x specifications are supported.
  1065. ** Note: b (binary) is a non-standard extension.
  1066. */
  1067. printf(argc) int argc; {
  1068.   return(_print(stdout, CCARGC() + &argc - 1));
  1069.   }
  1070.  
  1071. /*
  1072. ** _print(fd, ctlstring, arg, arg, ...)
  1073. ** Called by fprintf() and printf().
  1074. */
  1075. _print(fd, nxtarg) int fd, *nxtarg; {
  1076.   int  arg, left, pad, cc, len, maxchr, width;
  1077.   char *ctl, *sptr, str[17];
  1078.   cc = 0;                                         
  1079.   ctl = *nxtarg--;                          
  1080.   while(*ctl) {
  1081.     if(*ctl!='%') {fputc(*ctl++, fd); ++cc; continue;}
  1082.     else ++ctl;
  1083.     if(*ctl=='%') {fputc(*ctl++, fd); ++cc; continue;}
  1084.     if(*ctl=='-') {left = 1; ++ctl;} else left = 0;       
  1085.     if(*ctl=='0') pad = '0'; else pad = ' ';           
  1086.     if(isdigit(*ctl)) {
  1087.       width = atoi(ctl++);
  1088.       while(isdigit(*ctl)) ++ctl;
  1089.       }
  1090.     else width = 0;
  1091.     if(*ctl=='.') {            
  1092.       maxchr = atoi(++ctl);
  1093.       while(isdigit(*ctl)) ++ctl;
  1094.       }
  1095.     else maxchr = 0;
  1096.     arg = *nxtarg--;
  1097.     sptr = str;
  1098.     switch(*ctl++) {
  1099.       case 'c': str[0] = arg; str[1] = NULL; break;
  1100.       case 's': sptr = arg;        break;
  1101.       case 'd': itoa(arg,str);     break;
  1102.       case 'b': itoab(arg,str,2);  break;
  1103.       case 'o': itoab(arg,str,8);  break;
  1104.       case 'u': itoab(arg,str,10); break;
  1105.       case 'x': itoab(arg,str,16); break;
  1106.       default:  return (cc);
  1107.       }
  1108.     len = strlen(sptr);
  1109.     if(maxchr && maxchr<len) len = maxchr;
  1110.     if(width>len) width = width - len; else width = 0; 
  1111.     if(!left) while(width--) {fputc(pad,fd); ++cc;}
  1112.     while(len--) {fputc(*sptr++,fd); ++cc; }
  1113.     if(left) while(width--) {fputc(pad,fd); ++cc;}  
  1114.     }
  1115.   return(cc);
  1116.   }
  1117.  
  1118. >>> FPUTC.C 544
  1119. #include "stdio.h"
  1120. #include "clib.h"
  1121. extern int _status[];
  1122. /*
  1123. ** Character-stream output of a character to fd.
  1124. ** Entry: ch = Character to write.
  1125. **        fd = File descriptor of perinent file.
  1126. ** Returns character written on success, else EOF.
  1127. */
  1128. fputc(ch, fd) int ch, fd; {
  1129.   switch(ch) {
  1130.     case  EOF: _write(DOSEOF, fd); break;
  1131.     case '\n': _write(CR, fd); _write(LF, fd); break;
  1132.       default: _write(ch, fd);
  1133.     }
  1134.   if(_status[fd] & ERRBIT) return (EOF);
  1135.   return (ch);
  1136.   }
  1137. #asm
  1138. _putc:  jmp     _fputc
  1139.         public  _putc
  1140. #endasm
  1141.  
  1142. >>> FPUTS.C 264
  1143. #include "stdio.h"
  1144. #include "clib.h"
  1145. /*
  1146. ** Write a string to fd. 
  1147. ** Entry: string = Pointer to null-terminated string.
  1148. **        fd     = File descriptor of pertinent file.
  1149. */
  1150. fputs(string, fd) char *string; int fd; {
  1151.   while(*string) fputc(*string++, fd) ;
  1152.   }
  1153.  
  1154. >>> FREAD.C 887
  1155. #include "clib.h"
  1156. extern int _status[];
  1157. /*
  1158. ** Item-stream read from fd.
  1159. ** Entry: buf = address of target buffer
  1160. **         sz = size of items in bytes
  1161. **          n = number of items to read
  1162. **         fd = file descriptor
  1163. ** Returns a count of the items actually read.
  1164. ** Use feof() and ferror() to determine file status.
  1165. */
  1166. fread(buf, sz, n, fd) unsigned char *buf; unsigned sz, n, fd; {
  1167.   return (read(fd, buf, n*sz)/sz);
  1168.   }
  1169.  
  1170. /*
  1171. ** Binary-stream read from fd.
  1172. ** Entry:  fd = file descriptor
  1173. **        buf = address of target buffer
  1174. **          n = number of bytes to read
  1175. ** Returns a count of the bytes actually read.
  1176. ** Use feof() and ferror() to determine file status.
  1177. */
  1178. read(fd, buf, n) unsigned fd, n; unsigned char *buf; {
  1179.   unsigned cnt;
  1180.   cnt = 0;
  1181.   while(n--) {
  1182.     *buf++ = _read(fd);
  1183.     if(_status[fd] & (ERRBIT | EOFBIT)) break;
  1184.     ++cnt;
  1185.     }
  1186.   return (cnt);
  1187.   }
  1188.  
  1189. >>> FREE.C 374
  1190. extern char *_memptr;
  1191. /*
  1192. ** free(ptr) - Free previously allocated memory block.
  1193. ** Memory must be freed in the reverse order from which
  1194. ** it was allocated.
  1195. ** ptr    = Value returned by calloc() or malloc().
  1196. ** Returns ptr if successful or NULL otherwise.
  1197. */
  1198. free(ptr) char *ptr; {
  1199.    return (_memptr = ptr);
  1200.    }
  1201. #asm
  1202. _cfree: jmp     _free
  1203.         public  _cfree
  1204. #endasm
  1205.  
  1206. >>> FREOPEN.C 799
  1207. #include <stdio.h>
  1208. #include "clib.h"
  1209. /*
  1210. ** Close previously opened fd and reopen it. 
  1211. ** Entry: fn   = Null-terminated DOS file name.
  1212. **        mode = "a"  - append
  1213. **               "r"  - read
  1214. **               "w"  - write
  1215. **               "a+" - append update
  1216. **               "r+" - read   update
  1217. **               "w+" - write  update
  1218. **        fd   = File descriptor of pertinent file.
  1219. ** Returns the original fd on success, else NULL.
  1220. */
  1221. extern int _status[];
  1222. freopen(fn, mode, fd) char *fn, *mode; int fd; {
  1223.   int tfd;
  1224.   if(fclose(fd)) return (NULL);
  1225.   if(!_open(fn, mode, &tfd)) return (NULL);
  1226.   if(fd != tfd) {
  1227.     if(_bdos2(FORCE<<8, tfd, fd, NULL) < 0) return (NULL);
  1228.     _status[fd] = _status[tfd];
  1229.     _status[tfd] = 0;       /* leaves DOS using two handles */
  1230.     }
  1231.   return (fd);
  1232.   }
  1233.  
  1234. >>> FSCANF.C 2479
  1235. #include "stdio.h"
  1236. /*
  1237. ** fscanf(fd, ctlstring, arg, arg, ...) - Formatted read.
  1238. ** Operates as described by Kernighan & Ritchie.
  1239. ** b, c, d, o, s, u, and x specifications are supported.
  1240. ** Note: b (binary) is a non-standard extension.
  1241. */
  1242. fscanf(argc) int argc; {
  1243.   int *nxtarg;
  1244.   nxtarg = CCARGC() + &argc;
  1245.   return (_scan(*(--nxtarg), --nxtarg));
  1246.   }
  1247.  
  1248. /*
  1249. ** scanf(ctlstring, arg, arg, ...) - Formatted read.
  1250. ** Operates as described by Kernighan & Ritchie.
  1251. ** b, c, d, o, s, u, and x specifications are supported.
  1252. ** Note: b (binary) is a non-standard extension.
  1253. */
  1254. scanf(argc) int argc; {
  1255.   return (_scan(stdin, CCARGC() + &argc - 1));
  1256.   }
  1257.  
  1258. /*
  1259. ** _scan(fd, ctlstring, arg, arg, ...) - Formatted read.
  1260. ** Called by fscanf() and scanf().
  1261. */
  1262. _scan(fd,nxtarg) int fd, *nxtarg; {
  1263.   char *carg, *ctl;
  1264.   unsigned u;
  1265.   int  *narg, wast, ac, width, ch, cnv, base, ovfl, sign;
  1266.   ac = 0;
  1267.   ctl = *nxtarg--;
  1268.   while(*ctl) {
  1269.     if(isspace(*ctl)) {++ctl; continue;}
  1270.     if(*ctl++ != '%') continue;
  1271.     if(*ctl == '*') {narg = carg = &wast; ++ctl;}
  1272.     else             narg = carg = *nxtarg--;
  1273.     ctl += utoi(ctl, &width);
  1274.     if(!width) width = 32767;
  1275.     if(!(cnv = *ctl++)) break;
  1276.     while(isspace(ch = fgetc(fd))) ;
  1277.     if(ch == EOF) {if(ac) break; else return(EOF);}
  1278.     ungetc(ch,fd);
  1279.     switch(cnv) {
  1280.       case 'c':
  1281.         *carg = fgetc(fd);
  1282.         break;
  1283.       case 's':
  1284.         while(width--) {
  1285.           if((*carg = fgetc(fd)) == EOF) break;
  1286.           if(isspace(*carg)) break;
  1287.           if(carg != &wast) ++carg;
  1288.           }
  1289.         *carg = 0;
  1290.         break;
  1291.       default:
  1292.         switch(cnv) {
  1293.           case 'b': base =  2; sign = 1; ovfl = 32767; break;
  1294.           case 'd': base = 10; sign = 0; ovfl =  3276; break;
  1295.           case 'o': base =  8; sign = 1; ovfl =  8191; break;
  1296.           case 'u': base = 10; sign = 1; ovfl =  6553; break;
  1297.           case 'x': base = 16; sign = 1; ovfl =  4095; break;
  1298.           default:  return (ac);
  1299.           }
  1300.         *narg = u = 0;
  1301.         while(width-- && !isspace(ch=fgetc(fd)) && ch!=EOF) {
  1302.           if(!sign)
  1303.             if(ch == '-') {sign = -1; continue;}
  1304.             else sign = 1;
  1305.           if(ch < '0') return (ac);
  1306.           if(ch >= 'a')      ch -= 87;
  1307.           else if(ch >= 'A') ch -= 55;
  1308.           else               ch -= '0';
  1309.           if(ch >= base || u > ovfl) return (ac);
  1310.           u = u * base + ch;
  1311.           }
  1312.         *narg = sign * u;
  1313.       }
  1314.     ++ac;                          
  1315.     }
  1316.   return (ac);
  1317.   }
  1318.  
  1319. >>> FWRITE.C 959
  1320. #include "clib.h"
  1321. extern int _status[];
  1322. /*
  1323. ** Item-stream write to fd.
  1324. ** Entry: buf = address of source buffer
  1325. **         sz = size of items in bytes
  1326. **          n = number of items to write
  1327. **         fd = file descriptor
  1328. ** Returns a count of the items actually written or
  1329. ** zero if an error occurred.
  1330. ** May use ferror(), as always, to detect errors.
  1331. */
  1332. fwrite(buf, sz, n, fd) unsigned char *buf; unsigned sz, n, fd; {
  1333.   if(write(fd, buf, n*sz) == -1) return (0);
  1334.   return (n);
  1335.   }
  1336.  
  1337. /*
  1338. ** Binary-stream write to fd.
  1339. ** Entry:  fd = file descriptor
  1340. **        buf = address of source buffer
  1341. **          n = number of bytes to write
  1342. ** Returns a count of the bytes actually written or
  1343. ** -1 if an error occurred.
  1344. ** May use ferror(), as always, to detect errors.
  1345. */
  1346. write(fd, buf, n) unsigned fd, n; unsigned char *buf; {
  1347.   unsigned cnt;
  1348.   cnt = n;
  1349.   while(cnt--) {
  1350.     _write(*buf++, fd);
  1351.     if(_status[fd] & ERRBIT) return (-1);
  1352.     }
  1353.   return (n);
  1354.   }
  1355.  
  1356. >>> GETARG.C 626
  1357. #include "stdio.h"
  1358. /*
  1359. ** Get command line argument. 
  1360. ** Entry: n    = Number of the argument.
  1361. **        s    = Destination string pointer.
  1362. **        size = Size of destination string.
  1363. **        argc = Argument count from main().
  1364. **        argv = Argument vector(s) from main().
  1365. ** Returns number of characters moved on success,
  1366. ** else EOF.
  1367. */
  1368. getarg(n, s, size, argc, argv)
  1369.   int n; char *s; int size, argc, argv[]; {
  1370.   char *str;
  1371.   int i;
  1372.   if(n < 0 | n >= argc) {
  1373.     *s = NULL;
  1374.     return EOF;
  1375.     }
  1376.   i = 0;
  1377.   str=argv[n];
  1378.   while(i<size) {
  1379.     if((s[i]=str[i])==NULL) break;
  1380.     ++i;
  1381.     }
  1382.   s[i]=NULL;
  1383.   return i;
  1384.   }
  1385.  
  1386. >>> GETCHAR.C 111
  1387. #include "stdio.h"
  1388. /*
  1389. ** Get next character from standard input. 
  1390. */
  1391. getchar() {
  1392.   return (fgetc(stdin));
  1393.   }
  1394.  
  1395. >>> IS.C 2057
  1396. /*
  1397. ** All character classification functions except isascii().
  1398. ** Integer argument (c) must be in ASCII range (0-127) for
  1399. ** dependable answers.
  1400. */
  1401.  
  1402. #define ALNUM     1
  1403. #define ALPHA     2
  1404. #define CNTRL     4
  1405. #define DIGIT     8
  1406. #define GRAPH    16
  1407. #define LOWER    32
  1408. #define PRINT    64
  1409. #define PUNCT   128
  1410. #define BLANK   256
  1411. #define UPPER   512
  1412. #define XDIGIT 1024
  1413.  
  1414. int _is[128] = {
  1415.  0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004,
  1416.  0x004, 0x104, 0x104, 0x104, 0x104, 0x104, 0x004, 0x004,
  1417.  0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004,
  1418.  0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004, 0x004,
  1419.  0x140, 0x0D0, 0x0D0, 0x0D0, 0x0D0, 0x0D0, 0x0D0, 0x0D0,
  1420.  0x0D0, 0x0D0, 0x0D0, 0x0D0, 0x0D0, 0x0D0, 0x0D0, 0x0D0,
  1421.  0x459, 0x459, 0x459, 0x459, 0x459, 0x459, 0x459, 0x459,
  1422.  0x459, 0x459, 0x0D0, 0x0D0, 0x0D0, 0x0D0, 0x0D0, 0x0D0,
  1423.  0x0D0, 0x653, 0x653, 0x653, 0x653, 0x653, 0x653, 0x253,
  1424.  0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253,
  1425.  0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253, 0x253,
  1426.  0x253, 0x253, 0x253, 0x0D0, 0x0D0, 0x0D0, 0x0D0, 0x0D0,
  1427.  0x0D0, 0x473, 0x473, 0x473, 0x473, 0x473, 0x473, 0x073,
  1428.  0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073,
  1429.  0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073, 0x073,
  1430.  0x073, 0x073, 0x073, 0x0D0, 0x0D0, 0x0D0, 0x0D0, 0x004
  1431.  };
  1432.  
  1433. isalnum (c) int c; {return (_is[c] & ALNUM );} /* 'a'-'z', 'A'-'Z', '0'-'9' */
  1434. isalpha (c) int c; {return (_is[c] & ALPHA );} /* 'a'-'z', 'A'-'Z' */
  1435. iscntrl (c) int c; {return (_is[c] & CNTRL );} /* 0-31, 127 */
  1436. isdigit (c) int c; {return (_is[c] & DIGIT );} /* '0'-'9' */
  1437. isgraph (c) int c; {return (_is[c] & GRAPH );} /* '!'-'~' */
  1438. islower (c) int c; {return (_is[c] & LOWER );} /* 'a'-'z' */
  1439. isprint (c) int c; {return (_is[c] & PRINT );} /* ' '-'~' */
  1440. ispunct (c) int c; {return (_is[c] & PUNCT );} /* !alnum && !cntrl && !space */
  1441. isspace (c) int c; {return (_is[c] & BLANK );} /* HT, LF, VT, FF, CR, ' ' */
  1442. isupper (c) int c; {return (_is[c] & UPPER );} /* 'A'-'Z' */
  1443. isxdigit(c) int c; {return (_is[c] & XDIGIT);} /* '0'-'9', 'a'-'f', 'A'-'F' */
  1444.  
  1445. >>> ISASCII.C 108
  1446. /*
  1447. ** return 'true' if c is an ASCII character (0-127)
  1448. */
  1449. isascii(c) unsigned c; {
  1450.   return (c < 128);
  1451.   }
  1452.  
  1453. >>> ISATTY.C 374
  1454. /*
  1455. ** Return "true" if fd is a device, else "false"
  1456. */
  1457. isatty(fd) int fd; {
  1458. fd;               /* fetch handle */
  1459. #asm
  1460.   push bx         ; save 2nd reg
  1461.   mov  bx,ax      ; place handle
  1462.   mov  ax,4400h   ; ioctl get info function
  1463.   int 21h         ; call BDOS
  1464.   pop  bx         ; restore 2nd reg
  1465.   mov  ax,dx      ; fetch info bits
  1466.   and  ax,80h     ; isdev bit
  1467. #endasm
  1468.   }
  1469.  
  1470.  
  1471. >>> ISCONS.C 769
  1472. /*
  1473. ** Determine if fd is the console.
  1474. */
  1475. #include <stdio.h>
  1476. extern int _cons[];
  1477.  
  1478. iscons(fd) int fd; {
  1479.   if(_cons[fd] == NULL) {
  1480.     if(_iscons(fd)) _cons[fd] = 2;
  1481.     else            _cons[fd] = 1;
  1482.     }
  1483.   if(_cons[fd] == 1) return (NO);
  1484.   return (YES);
  1485.   }
  1486.  
  1487. /*
  1488. ** Call DOS only the first time for a file.
  1489. */
  1490. _iscons(fd) int fd; {
  1491.   fd;             /* fetch handle */
  1492. #asm
  1493.   push bx         ; save 2nd reg
  1494.   mov  bx,ax      ; place handle
  1495.   mov  ax,4400h   ; ioctl get info function
  1496.   int 21h         ; call BDOS
  1497.   pop  bx         ; restore 2nd reg
  1498.   mov  ax,dx      ; fetch info bits
  1499.   and  ax,83h     ; keep device and console bits
  1500.   cmp  ax,80h     ; device and console?
  1501.   jg   __cons1
  1502.   xor  ax,ax      ; return false if not device and console
  1503. __cons1:
  1504. #endasm
  1505.   }
  1506. >>> ITOA.C 276
  1507. /*
  1508. ** itoa(n,s) - Convert n to characters in s 
  1509. */
  1510. itoa(n, s) char *s; int n; {
  1511.   int sign;
  1512.   char *ptr;
  1513.   ptr = s;
  1514.   if ((sign = n) < 0) n = -n;
  1515.   do {
  1516.     *ptr++ = n % 10 + '0';
  1517.     } while ((n = n / 10) > 0);
  1518.   if (sign < 0) *ptr++ = '-';
  1519.   *ptr = '\0';
  1520.   reverse(s);
  1521.   }
  1522.  
  1523. >>> ITOAB.C 425
  1524. /*
  1525. ** itoab(n,s,b) - Convert "unsigned" n to characters in s using base b.
  1526. **                NOTE: This is a non-standard function.
  1527. */
  1528. itoab(n, s, b) int n; char *s; int b; {
  1529.   char *ptr;
  1530.   int lowbit;
  1531.   ptr = s;
  1532.   b >>= 1;
  1533.   do {
  1534.     lowbit = n & 1;
  1535.     n = (n >> 1) & 32767;
  1536.     *ptr = ((n % b) << 1) + lowbit;
  1537.     if(*ptr < 10) *ptr += '0'; else *ptr += 55;
  1538.     ++ptr;
  1539.     } while(n /= b);
  1540.   *ptr = 0;
  1541.   reverse (s);
  1542.   }
  1543.  
  1544. >>> ITOD.C 623
  1545. #include "stdio.h"
  1546. /*
  1547. ** itod -- convert nbr to signed decimal string of width sz
  1548. **         right adjusted, blank filled; returns str
  1549. **
  1550. **        if sz > 0 terminate with null byte
  1551. **        if sz = 0 find end of string
  1552. **        if sz < 0 use last byte for data
  1553. */
  1554. itod(nbr, str, sz)  int nbr;  char str[];  int sz;  {
  1555.   char sgn;
  1556.   if(nbr<0) {nbr = -nbr; sgn='-';}
  1557.   else sgn=' ';
  1558.   if(sz>0) str[--sz]=NULL;
  1559.   else if(sz<0) sz = -sz;
  1560.   else while(str[sz]!=NULL) ++sz;
  1561.   while(sz) {
  1562.     str[--sz]=(nbr%10+'0');
  1563.     if((nbr=nbr/10)==0) break;
  1564.     }
  1565.   if(sz) str[--sz]=sgn;
  1566.   while(sz>0) str[--sz]=' ';
  1567.   return str;
  1568.   }
  1569.  
  1570. >>> ITOO.C 541
  1571. /*
  1572. ** itoo -- converts nbr to octal string of length sz
  1573. **         right adjusted and blank filled, returns str
  1574. **
  1575. **        if sz > 0 terminate with null byte
  1576. **        if sz = 0 find end of string
  1577. **        if sz < 0 use last byte for data
  1578. */
  1579. itoo(nbr, str, sz)  int nbr;  char str[];  int sz;  {
  1580.   int digit;
  1581.   if(sz>0) str[--sz]=0;
  1582.   else if(sz<0) sz = -sz;
  1583.   else while(str[sz]!=0) ++sz;
  1584.   while(sz) {
  1585.     digit=nbr&7; nbr=(nbr>>3)&8191;
  1586.     str[--sz]=digit+48;
  1587.     if(nbr==0) break;
  1588.     }
  1589.   while(sz) str[--sz]=' ';
  1590.   return str;
  1591.   }
  1592.  
  1593. >>> ITOU.C 621
  1594. #include "stdio.h"
  1595. /*
  1596. ** itou -- convert nbr to unsigned decimal string of width sz
  1597. **         right adjusted, blank filled; returns str
  1598. **
  1599. **        if sz > 0 terminate with null byte
  1600. **        if sz = 0 find end of string
  1601. **        if sz < 0 use last byte for data
  1602. */
  1603. itou(nbr, str, sz)  int nbr;  char str[];  int sz;  {
  1604.   int lowbit;
  1605.   if(sz>0) str[--sz]=NULL;
  1606.   else if(sz<0) sz = -sz;
  1607.   else while(str[sz]!=NULL) ++sz;
  1608.   while(sz) {
  1609.     lowbit=nbr&1;
  1610.     nbr=(nbr>>1)&32767;  /* divide by 2 */
  1611.     str[--sz]=((nbr%5)<<1)+lowbit+'0';
  1612.     if((nbr=nbr/5)==0) break;
  1613.     }
  1614.   while(sz) str[--sz]=' ';
  1615.   return str;
  1616.   }
  1617.  
  1618. >>> ITOX.C 596
  1619. /*
  1620. ** itox -- converts nbr to hex string of length sz
  1621. **         right adjusted and blank filled, returns str
  1622. **
  1623. **        if sz > 0 terminate with null byte
  1624. **        if sz = 0 find end of string
  1625. **        if sz < 0 use last byte for data
  1626. */
  1627. itox(nbr, str, sz)  int nbr;  char str[];  int sz;  {
  1628.   int digit, offset;
  1629.   if(sz>0) str[--sz]=0;
  1630.   else if(sz<0) sz = -sz;
  1631.   else while(str[sz]!=0) ++sz;
  1632.   while(sz) {
  1633.     digit=nbr&15; nbr=(nbr>>4)&4095;
  1634.     if(digit<10) offset=48; else offset=55;
  1635.     str[--sz]=digit+offset;
  1636.     if(nbr==0) break;
  1637.     }
  1638.   while(sz) str[--sz]=' ';
  1639.   return str;
  1640.   }
  1641.  
  1642. >>> LEFT.C 166
  1643. /*
  1644. ** left -- left adjust and null terminate a string
  1645. */
  1646. left(str) char *str; {
  1647.   char *str2;
  1648.   str2=str;
  1649.   while(*str2==' ') ++str2;
  1650.   while(*str++ = *str2++);
  1651.   }
  1652.  
  1653. >>> LEXCMP.C 1380
  1654.  
  1655. char _lex[128] = {
  1656.        0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  /* NUL - /       */
  1657.       10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
  1658.       20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
  1659.       30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
  1660.       40, 41, 42, 43, 44, 45, 46, 47,
  1661.       65, 66, 67, 68, 69, 70, 71, 72, 73, 74,  /* 0-9           */
  1662.       48, 49, 50, 51, 52, 53, 54,              /* : ; < = > ? @ */
  1663.       75, 76, 77, 78, 79, 80, 81, 82, 83, 84,  /* A-Z           */
  1664.       85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
  1665.       95, 96, 97, 98, 99,100,
  1666.       55, 56, 57, 58, 59, 60,                  /* [ \ ] ^ _ `   */
  1667.       75, 76, 77, 78, 79, 80, 81, 82, 83, 84,  /* a-z           */
  1668.       85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
  1669.       95, 96, 97, 98, 99,100,
  1670.       61, 62, 63, 64,                          /* { | } ~       */
  1671.      127};                                     /* DEL           */
  1672.  
  1673. /*
  1674. ** lexcmp(s, t) - Return a number <0, 0, or >0
  1675. **                as s is <, =, or > t.
  1676. */
  1677. lexcmp(s, t) char *s, *t; {
  1678.   while(lexorder(*s, *t) == 0)
  1679.     if(*s++) ++t;
  1680.     else return (0);
  1681.   return (lexorder(*s, *t));
  1682.   }
  1683.  
  1684. /*
  1685. ** lexorder(c1, c2)
  1686. **
  1687. ** Return a negative, zero, or positive number if
  1688. ** c1 is less than, equal to, or greater than c2,
  1689. ** based on a lexicographical (dictionary order)
  1690. ** colating sequence.
  1691. **
  1692. */
  1693. lexorder(c1, c2) int c1, c2; {
  1694.   return(_lex[c1] - _lex[c2]);
  1695.   }
  1696.  
  1697. >>> MALLOC.C 237
  1698. #include "stdio.h"
  1699. /*
  1700. ** Memory allocation of size bytes.
  1701. ** size  = Size of the block in bytes.
  1702. ** Returns the address of the allocated block,
  1703. ** else NULL for failure.
  1704. */
  1705. malloc(size) unsigned size; {
  1706.   return (_alloc(size, NO));
  1707.   }
  1708.  
  1709. >>> OTOI.C 368
  1710. #include "stdio.h"
  1711. /*
  1712. ** otoi -- convert unsigned octal string to integer nbr
  1713. **          returns field size, else ERR on error
  1714. */
  1715. otoi(octstr, nbr)  char *octstr;  int *nbr;  {
  1716.   int d,t; d=0;
  1717.   *nbr=0;
  1718.   while((*octstr>='0')&(*octstr<='7')) {
  1719.     t=*nbr;
  1720.     t=(t<<3) + (*octstr++ - '0');
  1721.     if ((t>=0)&(*nbr<0)) return ERR;
  1722.     d++; *nbr=t;
  1723.     }
  1724.   return d;
  1725.   }
  1726.  
  1727. >>> PAD.C 123
  1728. /*
  1729. ** Place n occurrences of ch at dest.
  1730. */
  1731. pad(dest, ch, n) char *dest; unsigned n, ch; {
  1732.   while(n--) *dest++ = ch;
  1733.   }
  1734.  
  1735. >>> POLL.C 390
  1736. #include "stdio.h"
  1737. #include "clib.h"
  1738. /*
  1739. ** Poll for console input or interruption
  1740. */
  1741. poll(pause) int pause; {
  1742.   int i;
  1743.   if(i = _hitkey())  i = _getkey();
  1744.   if(pause) {
  1745.     if(i == PAUSE) {
  1746.       i = _getkey();           /* wait for next character */
  1747.       if(i == ABORT) exit(2);  /* indicate abnormal exit */
  1748.       return (0);
  1749.       }
  1750.     if(i == ABORT) exit(2);
  1751.     }
  1752.   return (i);
  1753.   }
  1754.  
  1755. >>> PUTCHAR.C 122
  1756. #include "stdio.h"
  1757. /*
  1758. ** Write character to standard output. 
  1759. */
  1760. putchar(ch) int ch; {
  1761.   return (fputc(ch, stdout));
  1762.   }
  1763.  
  1764. >>> PUTS.C 144
  1765. #include "stdio.h"
  1766. /*
  1767. ** Write string to standard output. 
  1768. */
  1769. puts(string) char *string; {
  1770.   fputs(string, stdout);
  1771.   fputc('\n', stdout);
  1772.   }
  1773.  
  1774. >>> RENAME.C 711
  1775. #include "stdio.h"
  1776. #include "clib.h"
  1777. /*
  1778. ** Rename a file.
  1779. **  from = address of old filename.
  1780. **    to = address of new filename.
  1781. **  Returns NULL on success, else ERR.
  1782. */
  1783. rename(from, to) char *from, *to; {
  1784.   if(_rename(from, to)) return (NULL);
  1785.   return (ERR);
  1786.   }
  1787.  
  1788. _rename(old, new) char *old, *new; {
  1789. #asm
  1790.   push ds         ; ds:dx points to old name
  1791.   pop  es         ; es:di points to new name
  1792.   mov  di,[bp+4]  ; get "new" offset
  1793.   mov  dx,[bp+6]  ; get "old" offset
  1794.   mov  ah,56h     ; rename function
  1795.   int  21h        ; call bdos
  1796.   jnc  __ren1     ; error?
  1797.   xor  ax,ax      ; yes, return false
  1798.   jmp  __ren2 
  1799. __ren1:           ; no, set hi and lo
  1800.   mov  ax,1       ; return true
  1801. __ren2:
  1802. #endasm
  1803.   }
  1804.  
  1805. >>> REVERSE.C 170
  1806. /*
  1807. ** reverse string in place 
  1808. */
  1809. reverse(s) char *s; {
  1810.   char *j;
  1811.   int c;
  1812.   j = s + strlen(s) - 1;
  1813.   while(s < j) {
  1814.     c = *s;
  1815.     *s++ = *j;
  1816.     *j-- = c;
  1817.     }
  1818.   }
  1819.  
  1820. >>> REWIND.C 89
  1821. /*
  1822. ** Rewind file to beginning. 
  1823. */
  1824. rewind(fd) int fd; {
  1825.   return(cseek(fd, 0, 0));
  1826.   }
  1827.  
  1828. >>> SIGN.C 154
  1829. /*
  1830. ** sign -- return -1, 0, +1 depending on the sign of nbr
  1831. */
  1832. sign(nbr)  int nbr;  {
  1833.   if(nbr > 0)  return 1;
  1834.   if(nbr == 0) return 0;
  1835.   return -1;
  1836.   }
  1837.  
  1838. >>> STRCAT.C 177
  1839. /*
  1840. ** concatenate t to end of s 
  1841. ** s must be large enough
  1842. */
  1843. strcat(s, t) char *s, *t; {
  1844.   char *d;
  1845.   d = s;
  1846.   --s;
  1847.   while (*++s) ;
  1848.   while (*s++ = *t++) ;
  1849.   return (d);
  1850.   }
  1851.  
  1852. >>> STRCHR.C 177
  1853. /*
  1854. ** return pointer to 1st occurrence of c in str, else 0
  1855. */
  1856. strchr(str, c) char *str, c; {
  1857.   while(*str) {
  1858.     if(*str == c) return (str);
  1859.     ++str;
  1860.     }
  1861.   return (0);
  1862.   }
  1863.  
  1864. >>> STRCMP.C 185
  1865. /*
  1866. ** return <0,   0,  >0 a_ording to
  1867. **       s<t, s=t, s>t
  1868. */
  1869. strcmp(s, t) char *s, *t; {
  1870.   while(*s == *t) {
  1871.     if(*s == 0) return (0);
  1872.     ++s; ++t;
  1873.     }
  1874.   return (*s - *t);
  1875.   }
  1876.  
  1877. >>> STRCPY.C 113
  1878. /*
  1879. ** copy t to s 
  1880. */
  1881. strcpy(s, t) char *s, *t; {
  1882.   char *d;
  1883.   d = s;
  1884.   while (*s++ = *t++) ;
  1885.   return (d);
  1886.   }
  1887.  
  1888. >>> STRLEN.C 357
  1889. /*
  1890. ** return length of string s (fast version)
  1891. */
  1892. strlen(s) char *s; {
  1893.   #asm
  1894.   xor al,al        ; set search value to zero
  1895.   mov cx,65535     ; set huge maximum
  1896.   mov di,[bp+4]    ; get address of s
  1897.   cld              ; set direction flag forward
  1898.   repne scasb      ; scan for zero
  1899.   mov ax,65534
  1900.   sub ax,cx        ; calc and return length
  1901.   #endasm
  1902.   }
  1903.  
  1904. >>> STRNCAT.C 255
  1905. /*
  1906. ** concatenate n bytes max from t to end of s 
  1907. ** s must be large enough
  1908. */
  1909. strncat(s, t, n) char *s, *t; int n; {
  1910.   char *d;
  1911.   d = s;
  1912.   --s;
  1913.   while(*++s) ;
  1914.   while(n--) {
  1915.     if(*s++ = *t++) continue;
  1916.     return(d);
  1917.     }
  1918.   *s = 0;
  1919.   return(d);
  1920.   }
  1921.  
  1922. >>> STRNCMP.C 333
  1923. /*
  1924. ** strncmp(s,t,n) - Compares two strings for at most n
  1925. **                  characters and returns an integer
  1926. **                  >0, =0, or <0 as s is >t, =t, or <t.
  1927. */
  1928. strncmp(s, t, n) char *s, *t; int n; {
  1929.   while(n && *s==*t) {
  1930.     if (*s == 0) return (0);
  1931.     ++s; ++t; --n;
  1932.     }
  1933.   if(n) return (*s - *t);
  1934.   return (0);
  1935.   }
  1936.  
  1937. >>> STRNCPY.C 253
  1938. /*
  1939. ** copy n characters from sour to dest (null padding)
  1940. */
  1941. strncpy(dest, sour, n) char *dest, *sour; int n; {
  1942.   char *d;
  1943.   d = dest;
  1944.   while(n-- > 0) {
  1945.     if(*d++ = *sour++) continue;
  1946.     while(n-- > 0) *d++ = 0;
  1947.     }
  1948.   *d = 0;
  1949.   return (dest);
  1950.   }
  1951.  
  1952. >>> STRRCHR.C 315
  1953. /*
  1954. ** strrchr(s,c) - Search s for rightmost occurrance of c.
  1955. ** s      = Pointer to string to be searched.
  1956. ** c      = Character to search for.
  1957. ** Returns pointer to rightmost c or NULL.
  1958. */
  1959. strrchr(s, c) char *s, c; {
  1960.   char *ptr;
  1961.   ptr = 0;
  1962.   while(*s) {
  1963.     if(*s==c) ptr = s;
  1964.     ++s;
  1965.     }
  1966.   return (ptr);
  1967.   }
  1968.  
  1969. >>> TOASCII.C 77
  1970. /*
  1971. ** return ASCII equivalent of c
  1972. */
  1973. toascii(c) int c; {
  1974.   return (c);
  1975.   }
  1976.  
  1977. >>> TOLOWER.C 131
  1978. /*
  1979. ** return lower-case of c if upper-case, else c
  1980. */
  1981. tolower(c) int c; {
  1982.   if(c<='Z' && c>='A') return (c+32);
  1983.   return (c);
  1984.   }
  1985.  
  1986. >>> TOUPPER.C 137
  1987. /*
  1988. ** return upper-case of c if it is lower-case, else c
  1989. */
  1990. toupper(c) int c; {
  1991.   if(c<='z' && c>='a') return (c-32);
  1992.   return (c);
  1993.   }
  1994.  
  1995. >>> UNGETC.C 295
  1996. #include "stdio.h"
  1997. extern _nextc[];
  1998. /*
  1999. ** Put c back into file fd.
  2000. ** Entry:  c = character to put back
  2001. **        fd = file descriptor
  2002. ** Returns c if successful, else EOF.
  2003. */
  2004. ungetc(c, fd) int c, fd; {
  2005.   if(!_mode(fd) || _nextc[fd]!=EOF || c==EOF) return (EOF);
  2006.   return (_nextc[fd] = c);
  2007.   }
  2008.  
  2009. >>> UNLINK.C 473
  2010. #include "stdio.h"
  2011. #include "clib.h"
  2012. /*
  2013. ** Unlink (delete) the named file. 
  2014. ** Entry: fn = Null-terminated DOS file path\name.
  2015. ** Returns NULL on success, else ERR.
  2016. */
  2017. unlink(fn) char *fn; {
  2018.   fn;           /* load fn into ax */
  2019. #asm
  2020.   mov dx,ax     ; put fn in its place
  2021.   mov ah,41h    ; delete function code
  2022.   int 21h
  2023.   mov ax,0
  2024.   jnc __unlk    ; return NULL
  2025.   mov ax,-2     ; return ERR
  2026. __unlk:
  2027. #endasm
  2028.   }
  2029. #asm
  2030. _delete: jmp    _unlink
  2031.          public _delete
  2032. #endasm
  2033.  
  2034. >>> UTOI.C 365
  2035. #include "stdio.h"
  2036. /*
  2037. ** utoi -- convert unsigned decimal string to integer nbr
  2038. **          returns field size, else ERR on error
  2039. */
  2040. utoi(decstr, nbr)  char *decstr;  int *nbr;  {
  2041.   int d,t; d=0;
  2042.   *nbr=0;
  2043.   while((*decstr>='0')&(*decstr<='9')) {
  2044.     t=*nbr;t=(10*t) + (*decstr++ - '0');
  2045.     if ((t>=0)&(*nbr<0)) return ERR;
  2046.     d++; *nbr=t;
  2047.     }
  2048.   return d;
  2049.   }
  2050.  
  2051. >>> XTOI.C 729
  2052. #include stdio.h
  2053. /*
  2054. ** xtoi -- convert hex string to integer nbr
  2055. **         returns field size, else ERR on error
  2056. */
  2057. xtoi(hexstr, nbr) char *hexstr; int *nbr; {
  2058.   int d, b;  char *cp;
  2059.   d = *nbr = 0; cp = hexstr;
  2060.   while(*cp == '0') ++cp;
  2061.   while(1) {
  2062.     switch(*cp) {
  2063.       case '0': case '1': case '2':
  2064.       case '3': case '4': case '5':
  2065.       case '6': case '7': case '8':
  2066.       case '9':                     b=48; break;
  2067.       case 'A': case 'B': case 'C':
  2068.       case 'D': case 'E': case 'F': b=55; break;
  2069.       case 'a': case 'b': case 'c':
  2070.       case 'd': case 'e': case 'f': b=87; break;
  2071.        default: return (cp - hexstr);
  2072.       }
  2073.     if(d < 4) ++d; else return (ERR);
  2074.     *nbr = (*nbr << 4) + (*cp++ - b);
  2075.     }
  2076.   }
  2077.